CharIntervalDescriptor = (
    first : CharLiteral,
    last : CharLiteral
)

CharClassDescriptor = (
    isNegated : bool,
    intervals : [CharIntervalDescriptor]
)

LexicalExpression:
    Empty
    String (value : StringLiteral)
    QuoteString (value : StringLiteral)
    CharClass (value : CharClassDescriptor)
    NameReference (name : Identifier)
    Kleene (operand : LexicalExpression)
    Optional (operand : LexicalExpression)
    Positive (operand : LexicalExpression)
    Repeat (operand : LexicalExpression, minCount : IntegerLiteral?, maxCount : IntegerLiteral?)
    Concat (left : LexicalExpression, right : LexicalExpression)
    Union (left : LexicalExpression, right : LexicalExpression)

LexicalAliasDeclarator = (
    name : Identifier,
    pattern : LexicalExpression
)

LexicalStartReferenceSet = (
    names : [Identifier],
    includesNonExclusive : bool,
    includesAll : bool
)

LexicalRuleDeclarator = (
    atLineBegin : bool,
    pattern : LexicalExpression,
    atLineEnd : bool,
    action : SemanticAction?
)

LexicalStartDeclarator = (
    starts : LexicalStartReferenceSet,
    rules : [LexicalRuleDeclarator],
    defaultAction : SemanticAction?
)

LexicalDeclarator:
    Alias (declarator : LexicalAliasDeclarator)
    Start (declarator : LexicalStartDeclarator)

LexicalDeclaration = (declarators : [LexicalDeclarator])

%%

CharIntervalEndPoint as CharLiteral:
    QuoteStringLiteral => CharLiteral.New($1.AsSingle, @1)

CharInterval as CharIntervalDescriptor:
    CharIntervalEndPoint => CharIntervalDescriptor.New($1, $1, @1)
    CharIntervalEndPoint '-' CharIntervalEndPoint => CharIntervalDescriptor.New($1, $3, @@)

CharClassLiteral as CharClassDescriptor:
    '[' CharInterval* ']' => CharClassDescriptor.New(False, $2, @@)
    '[' '^' CharInterval* ']' => CharClassDescriptor.New(True, $3, @@)

PrimaryLexicalExpression as LexicalExpression:
    StringLiteral => LexicalExpression.NewString($1, @1)
    QuoteStringLiteral => LexicalExpression.NewQuoteString($1, @1)
    CharClassLiteral => LexicalExpression.NewCharClass($1, @1)
    Name => LexicalExpression.NewNameReference($1, @1)
    '(' ')' => LexicalExpression.NewEmpty(@@)
    '(' LexicalExpression ')' => $2

PostfixLexicalExpression as LexicalExpression:
    PrimaryLexicalExpression => $1
    PostfixLexicalExpression '*' => LexicalExpression.NewKleene($1, @@)
    PostfixLexicalExpression '?' => LexicalExpression.NewOptional($1, @@)
    PostfixLexicalExpression '+' => LexicalExpression.NewPositive($1, @@)
    PostfixLexicalExpression '{' IntegerLiteral '}' => LexicalExpression.NewRepeat($1, $3, $3, @@)
    PostfixLexicalExpression '{' ',' IntegerLiteral '}' => LexicalExpression.NewRepeat($1, None, $4, @@)
    PostfixLexicalExpression '{' IntegerLiteral ',' '}' => LexicalExpression.NewRepeat($1, $3, None, @@)
    PostfixLexicalExpression '{' IntegerLiteral ',' IntegerLiteral '}' => LexicalExpression.NewRepeat($1, $3, $5, @@)

ConcatLexicalExpression as LexicalExpression:
    PostfixLexicalExpression => $1
    ConcatLexicalExpression PostfixLexicalExpression => LexicalExpression.NewConcat($1, $2, @@)

LexicalExpression as LexicalExpression:
    ConcatLexicalExpression => $1
    LexicalExpression '|' ConcatLexicalExpression => LexicalExpression.NewUnion($1, $3, @@)

LexicalAliasDeclarator as LexicalAliasDeclarator:
    Name '=' LexicalExpression NewLine => LexicalAliasDeclarator.New($1, $3, @@)

LexicalStartReferenceSet as LexicalStartReferenceSet:
    Name => LexicalStartReferenceSet.New(Sequence.Create($1), False, False, @@)
    '<' '**' '>' => LexicalStartReferenceSet.New(default([Identifier]), False, True, @@)
    '<' '*' '>' => LexicalStartReferenceSet.New(default([Identifier]), True, False, @@)
    '<' Name %+ ',' '>' => LexicalStartReferenceSet.New($2, False, False, @@)
    '<' Name %+ ',' ',' '*' '>' => LexicalStartReferenceSet.New($2, True, False, @@)

LexicalRuleDeclarator as LexicalRuleDeclarator:
    LexicalExpression NewLine => LexicalRuleDeclarator.New(False, $1, False, None, @@)
    LexicalExpression '$' NewLine => LexicalRuleDeclarator.New(False, $1, True, None, @@)
    '^' LexicalExpression NewLine => LexicalRuleDeclarator.New(True, $2, False, None, @@)
    '^' LexicalExpression '$' NewLine => LexicalRuleDeclarator.New(True, $2, True, None, @@)
    LexicalExpression SemanticAction => LexicalRuleDeclarator.New(False, $1, False, $2, @@)
    LexicalExpression '$' SemanticAction => LexicalRuleDeclarator.New(False, $1, True, $3, @@)
    '^' LexicalExpression SemanticAction => LexicalRuleDeclarator.New(True, $2, False, $3, @@)
    '^' LexicalExpression '$' SemanticAction => LexicalRuleDeclarator.New(True, $2, True, $4, @@)

LexicalStartDeclarator as LexicalStartDeclarator:
    LexicalStartReferenceSet ':' 'pass' NewLine => LexicalStartDeclarator.New($1, default([LexicalRuleDeclarator]), None, @@)
    LexicalStartReferenceSet ':' NewLine Indent 'pass' NewLine Unindent => LexicalStartDeclarator.New($1, default([LexicalRuleDeclarator]), None, @@)
    LexicalStartReferenceSet ':' NewLine Indent LexicalRuleDeclarator+ Unindent => LexicalStartDeclarator.New($1, $5, None, @@)
    LexicalStartReferenceSet ':' NewLine Indent LexicalRuleDeclarator+ 'default' SemanticAction Unindent => LexicalStartDeclarator.New($1, $5, $7, @@)
    LexicalStartReferenceSet ':' NewLine Indent 'default' SemanticAction Unindent => LexicalStartDeclarator.New($1, default([LexicalRuleDeclarator]), $6, @@)

LexicalDeclarator as LexicalDeclarator:
    LexicalAliasDeclarator => LexicalDeclarator.NewAlias($1, @1)
    LexicalStartDeclarator => LexicalDeclarator.NewStart($1, @1)

LexicalDeclaration as LexicalDeclaration:
    LexicalDeclarator* => LexicalDeclaration.New($1, @1)
